<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>微信支付与即时通讯开发指南 | 技术小馆</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        :root {
            --primary: #1a56db;
            --primary-light: #e1e9f8;
            --secondary: #6c757d;
            --accent: #10b981;
            --dark: #1f2937;
            --light: #f9fafb;
        }
        
        body {
            font-family: 'Noto Sans SC', 'Noto Serif SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            line-height: 1.6;
            color: var(--dark);
            background-color: #fff;
        }
        
        .hero {
            background: linear-gradient(135deg, #1a56db 0%, #3b82f6 100%);
            color: white;
        }
        
        .code-block {
            background: #282c34;
            border-radius: 8px;
            overflow: hidden;
        }
        
        .code-header {
            background: #21252b;
            color: #9da5b4;
            padding: 0.5rem 1rem;
            font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
            font-size: 0.9rem;
            display: flex;
            justify-content: space-between;
        }
        
        pre {
            margin: 0;
            padding: 1rem;
            overflow-x: auto;
        }
        
        code {
            font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
            font-size: 0.9rem;
            color: #abb2bf;
        }
        
        .note {
            border-left: 4px solid var(--accent);
            background-color: var(--primary-light);
            padding: 1rem;
            margin: 1rem 0;
            border-radius: 0 4px 4px 0;
        }
        
        .feature-card {
            transition: all 0.3s ease;
            border-radius: 8px;
            overflow: hidden;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
        }
        
        .feature-card:hover {
            transform: translateY(-4px);
            box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
        }
        
        .table-container {
            overflow-x: auto;
        }
        
        table {
            width: 100%;
            border-collapse: collapse;
        }
        
        th, td {
            padding: 0.75rem;
            text-align: left;
            border-bottom: 1px solid #e5e7eb;
        }
        
        th {
            background-color: var(--primary-light);
            font-weight: 600;
        }
        
        tr:hover {
            background-color: #f8f9fa;
        }
        
        .footer {
            background-color: #111827;
            color: #f3f4f6;
        }
        
        .footer a:hover {
            color: #60a5fa;
        }
        
        .step {
            position: relative;
            padding-left: 2.5rem;
            margin-bottom: 1.5rem;
        }
        
        .step:before {
            content: '';
            position: absolute;
            left: 0;
            top: 0;
            width: 24px;
            height: 24px;
            border-radius: 50%;
            background-color: var(--primary);
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
        }
        
        .step-1:before { content: '1'; }
        .step-2:before { content: '2'; }
        .step-3:before { content: '3'; }
        .step-4:before { content: '4'; }
        
        .step-content {
            padding: 1rem;
            background-color: white;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
        }
    </style>
</head>
<body>
    <!-- Hero Section -->
    <section class="hero py-16 md:py-24 px-4 md:px-0">
        <div class="container mx-auto max-w-5xl text-center">
            <h1 class="text-4xl md:text-5xl font-bold mb-4">微信支付与即时通讯开发指南</h1>
            <p class="text-xl md:text-2xl opacity-90 mb-8">一站式掌握微信支付与WebSocket即时通讯核心技术</p>
            <div class="flex flex-wrap justify-center gap-4">
                <a href="#wechat-pay" class="bg-white text-primary px-6 py-3 rounded-full font-medium hover:bg-gray-100 transition duration-300">
                    <i class="fab fa-weixin mr-2"></i>微信支付开发
                </a>
                <a href="#goeasy" class="bg-white text-primary px-6 py-3 rounded-full font-medium hover:bg-gray-100 transition duration-300">
                    <i class="fas fa-comments mr-2"></i>GoEasy即时通讯
                </a>
                <a href="#zxing" class="bg-white text-primary px-6 py-3 rounded-full font-medium hover:bg-gray-100 transition duration-300">
                    <i class="fas fa-qrcode mr-2"></i>ZXing二维码处理
                </a>
            </div>
        </div>
    </section>

    <!-- Main Content -->
    <main class="container mx-auto max-w-5xl px-4 py-12">
        <!-- WeChat Pay Section -->
        <section id="wechat-pay" class="mb-16">
            <div class="flex items-center mb-8">
                <i class="fab fa-weixin text-4xl text-green-600 mr-4"></i>
                <h2 class="text-3xl font-bold">微信支付开发文档</h2>
            </div>
            
            <div class="bg-white rounded-xl shadow-sm p-6 mb-8">
                <p class="text-lg mb-4">官方文档链接: <a href="https://pay.weixin.qq.com/wiki/doc/api/index.html" class="text-primary hover:underline" target="_blank">https://pay.weixin.qq.com/wiki/doc/api/index.html</a></p>
                
                <div class="flex items-center justify-center my-8">
                    <div class="text-center">
                        <img src="https://cdn.nlark.com/yuque/0/2025/png/21449790/1741349953859-6d67fbb5-7b8a-49af-93a2-9ebd16fddc97.png" alt="微信支付Demo" class="rounded-lg shadow-md mx-auto mb-4 max-w-xs">
                        <p class="text-gray-600">微信支付Demo示例下载</p>
                    </div>
                </div>
                
                <div class="note">
                    <p><strong>注意事项:</strong></p>
                    <ul class="list-disc pl-5 mt-2">
                        <li>证书文件不能放在web服务器虚拟目录，应放在有访问权限控制的目录中</li>
                        <li>建议将证书文件名改为复杂且不容易猜测的文件名</li>
                        <li>商户服务器要做好病毒和木马防护工作，不被非法侵入者窃取证书文件</li>
                        <li>请妥善保管商户支付密钥、公众帐号SECRET，避免密钥泄露</li>
                    </ul>
                </div>
            </div>
            
            <!-- Configuration Section -->
            <div class="mb-12">
                <h3 class="text-2xl font-semibold mb-6 border-b pb-2">配置开发者信息</h3>
                
                <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
                    <!-- QfWxConfig -->
                    <div class="feature-card bg-white">
                        <div class="code-block">
                            <div class="code-header">
                                <span>QfWxConfig.java</span>
                                <span class="text-xs">微信支付配置类</span>
                            </div>
                            <pre><code class="language-java">public class QfWxConfig extends WXPayConfig {

    @Override
    public String getAppID() {
        return "wx632c8f211f8122c6"; // 设置应用ID
    }

    @Override
    String getMchID() {
        return "1497984412"; // 设置商户Id
    }

    @Override
    String getKey() {
        return "sbNCm1JnevqI36LrEaxFwcaT0hkGxFnC"; // api秘钥
    }

    @Override
    InputStream getCertStream() {
        return null;
    }

    @Override
    IWXPayDomain getWXPayDomain() {
        return new QfWxDomain();
    }
}</code></pre>
                        </div>
                    </div>
                    
                    <!-- QfWxDomain -->
                    <div class="feature-card bg-white">
                        <div class="code-block">
                            <div class="code-header">
                                <span>QfWxDomain.java</span>
                                <span class="text-xs">微信支付域名配置</span>
                            </div>
                            <pre><code class="language-java">public class QfWxDomain implements IWXPayDomain {
    @Override
    public void report(String domain, long elapsedTimeMillis, Exception ex) {
    }

    @Override
    public DomainInfo getDomain(WXPayConfig config) {
        return new DomainInfo("api.mch.weixin.qq.com",true);
    }
}</code></pre>
                        </div>
                    </div>
                </div>
            </div>
            
            <!-- API Methods -->
            <div class="mb-12">
                <h3 class="text-2xl font-semibold mb-6 border-b pb-2">微信支付 Java SDK API</h3>
                
                <div class="table-container bg-white rounded-lg shadow-sm overflow-hidden">
                    <table class="w-full">
                        <thead>
                            <tr>
                                <th>方法名</th>
                                <th>说明</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td>microPay</td>
                                <td>刷卡支付</td>
                            </tr>
                            <tr>
                                <td>unifiedOrder</td>
                                <td>统一下单</td>
                            </tr>
                            <tr>
                                <td>orderQuery</td>
                                <td>查询订单</td>
                            </tr>
                            <tr>
                                <td>reverse</td>
                                <td>撤销订单</td>
                            </tr>
                            <tr>
                                <td>closeOrder</td>
                                <td>关闭订单</td>
                            </tr>
                            <tr>
                                <td>refund</td>
                                <td>申请退款</td>
                            </tr>
                            <tr>
                                <td>refundQuery</td>
                                <td>查询退款</td>
                            </tr>
                            <tr>
                                <td>downloadBill</td>
                                <td>下载对账单</td>
                            </tr>
                            <tr>
                                <td>report</td>
                                <td>交易保障</td>
                            </tr>
                            <tr>
                                <td>shortUrl</td>
                                <td>转换短链接</td>
                            </tr>
                            <tr>
                                <td>authCodeToOpenid</td>
                                <td>授权码查询openid</td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
            
            <!-- Examples -->
            <div class="mb-12">
                <h3 class="text-2xl font-semibold mb-6 border-b pb-2">使用示例</h3>
                
                <div class="space-y-8">
                    <!-- MyConfig -->
                    <div class="feature-card bg-white">
                        <div class="code-block">
                            <div class="code-header">
                                <span>MyConfig.java</span>
                                <span class="text-xs">带证书的配置类</span>
                            </div>
                            <pre><code class="language-java">import com.github.wxpay.sdk.WXPayConfig;
import java.io.*;

public class MyConfig implements WXPayConfig{

    private byte[] certData;

    public MyConfig() throws Exception {
        String certPath = "/path/to/apiclient_cert.p12";
        File file = new File(certPath);
        InputStream certStream = new FileInputStream(file);
        this.certData = new byte[(int) file.length()];
        certStream.read(this.certData);
        certStream.close();
    }

    public String getAppID() {
        return "wx8888888888888888";
    }

    public String getMchID() {
        return "12888888";
    }

    public String getKey() {
        return "88888888888888888888888888888888";
    }

    public InputStream getCertStream() {
        ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
        return certBis;
    }

    public int getHttpConnectTimeoutMs() {
        return 8000;
    }

    public int getHttpReadTimeoutMs() {
        return 10000;
    }
}</code></pre>
                        </div>
                    </div>
                    
                    <!-- Unified Order -->
                    <div class="feature-card bg-white">
                        <div class="code-block">
                            <div class="code-header">
                                <span>统一下单示例</span>
                                <span class="text-xs">WXPayExample.java</span>
                            </div>
                            <pre><code class="language-java">import com.github.wxpay.sdk.WXPay;
import java.util.HashMap;
import java.util.Map;

public class WXPayExample {
    public static void main(String[] args) throws Exception {
        MyConfig config = new MyConfig();
        WXPay wxpay = new WXPay(config);

        Map&lt;String, String&gt; data = new HashMap&lt;String, String&gt;();
        data.put("body", "腾讯充值中心-QQ会员充值");
        data.put("out_trade_no", "2016090910595900000012");
        data.put("device_info", "");
        data.put("fee_type", "CNY");
        data.put("total_fee", "1");
        data.put("spbill_create_ip", "123.12.12.123");
        data.put("notify_url", "http://www.example.com/wxpay/notify");
        data.put("trade_type", "NATIVE");  // 此处指定为扫码支付
        data.put("product_id", "12");

        try {
            Map&lt;String, String&gt; resp = wxpay.unifiedOrder(data);
            System.out.println(resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}</code></pre>
                        </div>
                    </div>
                    
                    <!-- Order Query -->
                    <div class="feature-card bg-white">
                        <div class="code-block">
                            <div class="code-header">
                                <span>订单查询示例</span>
                                <span class="text-xs">WXPayExample.java</span>
                            </div>
                            <pre><code class="language-java">import com.github.wxpay.sdk.WXPay;
import java.util.HashMap;
import java.util.Map;

public class WXPayExample {
    public static void main(String[] args) throws Exception {
        MyConfig config = new MyConfig();
        WXPay wxpay = new WXPay(config);

        Map&lt;String, String&gt; data = new HashMap&lt;String, String&gt;();
        data.put("out_trade_no", "2016090910595900000012");

        try {
            Map&lt;String, String&gt; resp = wxpay.orderQuery(data);
            System.out.println(resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}</code></pre>
                        </div>
                    </div>
                    
                    <!-- Notification -->
                    <div class="feature-card bg-white">
                        <div class="code-block">
                            <div class="code-header">
                                <span>支付结果通知验证</span>
                                <span class="text-xs">WXPayExample.java</span>
                            </div>
                            <pre><code class="language-java">import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import java.util.Map;

public class WXPayExample {
    public static void main(String[] args) throws Exception {
        String notifyData = "...."; // 支付结果通知的xml格式数据
        MyConfig config = new MyConfig();
        WXPay wxpay = new WXPay(config);
        Map&lt;String, String&gt; notifyMap = WXPayUtil.xmlToMap(notifyData);

        if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {
            // 签名正确，进行处理
        } else {
            // 签名错误
        }
    }
}</code></pre>
                        </div>
                    </div>
                </div>
            </div>
        </section>
        
        <!-- ZXing Section -->
        <section id="zxing" class="mb-16">
            <div class="flex items-center mb-8">
                <i class="fas fa-qrcode text-4xl text-blue-600 mr-4"></i>
                <h2 class="text-3xl font-bold">ZXing二维码处理</h2>
            </div>
            
            <div class="bg-white rounded-xl shadow-sm p-6 mb-8">
                <h3 class="text-xl font-semibold mb-4">ZXing简介</h3>
                <p class="mb-4">ZXing是一个开源的，用Java实现的多种格式的1D/2D条码图像处理库，它包含了联系到其他语言的端口。zxing可以实现使用手机的内置的摄像头完成条形码的扫描及解码。</p>
                
                <div class="note">
                    <p><strong>ZXing可以完成以下功能:</strong></p>
                    <ul class="list-disc pl-5 mt-2">
                        <li>通过摄像头扫描二维码图片，读取图片内容</li>
                        <li>从相册中选取二维码图片，读取图片内容</li>
                        <li>自己输入字符串内容，生成二维码图片</li>
                        <li>长按识别自己生成的二维码图片</li>
                    </ul>
                </div>
                
                <h3 class="text-xl font-semibold mb-4 mt-8">Maven依赖</h3>
                <div class="code-block mb-6">
                    <div class="code-header">
                        <span>pom.xml</span>
                        <span class="text-xs">ZXing依赖配置</span>
                    </div>
                    <pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;com.google.zxing&lt;/groupId&gt;
    &lt;artifactId&gt;core&lt;/artifactId&gt;
    &lt;version&gt;3.3.3&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
    &lt;groupId&gt;com.google.zxing&lt;/groupId&gt;
    &lt;artifactId&gt;javase&lt;/artifactId&gt;
    &lt;version&gt;3.3.3&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
                </div>
                
                <h3 class="text-xl font-semibold mb-4">使用示例</h3>
                <div class="code-block">
                    <div class="code-header">
                        <span>QRCodeUtils.java</span>
                        <span class="text-xs">二维码生成与识别工具类</span>
                    </div>
                    <pre><code class="language-java">public class QRCodeUtils {

    public static String out ="./demo.png";

    public static void main(String[] args) throws Exception {
//        QREncodeLog();
        QRReader(new File("./demo.png"));
    }

    /**
     * 生成二维码带log
     */
    public static void QREncodeLog() throws WriterException, IOException {
        String content = "带log的二维码";
        int width = 200; // 图像宽度
        int height = 200; // 图像高度
        String format = "png";// 图像类型
        Map&lt;EncodeHintType, Object&gt; hints = new HashMap&lt;&gt;();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
        MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF);
        BufferedImage bufferedImage = LogoMatrix(MatrixToImageWriter.toBufferedImage(bitMatrix,matrixToImageConfig), new File("C:\\Users\\dashixin\\Pictures\\B站\\RabbitMQ.png"));
        ImageIO.write(bufferedImage, "png", new File(out));
        System.out.println("输出成功.");
    }

    /**
     * 识别二维码
     */
    public static void QRReader(File file) throws IOException, NotFoundException {
        MultiFormatReader formatReader = new MultiFormatReader();
        BufferedImage bufferedImage = ImageIO.read(file);
        BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(bufferedImage)));
        Map hints = new HashMap&lt;&gt;();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        com.google.zxing.Result result = formatReader.decode(binaryBitmap, hints);
        System.out.println("解析结果：" + result.toString());
        System.out.println("二维码格式类型：" + result.getBarcodeFormat());
        System.out.println("二维码文本内容：" + result.getText());
        bufferedImage.flush();
    }

    /**
     * 二维码添加logo
     */
    public static BufferedImage LogoMatrix(BufferedImage matrixImage, File logoFile) throws IOException {
        Graphics2D g2 = matrixImage.createGraphics();
        int matrixWidth = matrixImage.getWidth();
        int matrixHeigh = matrixImage.getHeight();
        BufferedImage logo = ImageIO.read(logoFile);
        g2.drawImage(logo, matrixWidth / 5 * 2, matrixHeigh / 5 * 2, matrixWidth / 5, matrixHeigh / 5, null);
        BasicStroke stroke = new BasicStroke(5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        g2.setStroke(stroke);
        RoundRectangle2D.Float round = new RoundRectangle2D.Float(matrixWidth / 5 * 2, matrixHeigh / 5 * 2, matrixWidth / 5, matrixHeigh / 5, 20, 20);
        g2.setColor(Color.white);
        g2.draw(round);
        BasicStroke stroke2 = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        g2.setStroke(stroke2);
        RoundRectangle2D.Float round2 = new RoundRectangle2D.Float(matrixWidth / 5 * 2 + 2, matrixHeigh / 5 * 2 + 2, matrixWidth / 5 - 4, matrixHeigh / 5 - 4, 20, 20);
        g2.setColor(new Color(128, 128, 128));
        g2.draw(round2);
        g2.dispose();
        matrixImage.flush();
        return matrixImage;
    }
}</code></pre>
                </div>
            </div>
        </section>
        
        <!-- GoEasy Section -->
        <section id="goeasy" class="mb-16">
            <div class="flex items-center mb-8">
                <i class="fas fa-comments text-4xl text-purple-600 mr-4"></i>
                <h2 class="text-3xl font-bold">GoEasy即时通讯</h2>
            </div>
            
            <div class="bg-white rounded-xl shadow-sm p-6 mb-8">
                <div class="flex items-center mb-4">
                    <a href="https://www.goeasy.io/" class="text-primary hover:underline" target="_blank">https://www.goeasy.io/</a>
                </div>
                
                <p class="mb-4">GoEasy专注于服务器与浏览器,浏览器与浏览器之间消息推送,完美兼容世界上的绝大多数浏览器,包括IE6, IE7之类的非常古老的浏览器。 GoEasy采用 发布/订阅 的消息模式,帮助您非常轻松的实现一对一,一对多的通信。</p>
                
                <div class="note">
                    <p>GoEasy是一款强大易用的websocket消息推送服务，web端,移动端都可以进行推送，这是个收费的产品，当然提供12个月免费试用期，针对不同的并发数量和消息发送条数都有价格明细。</p>
                </div>
                
                <h3 class="text-xl font-semibold mb-4 mt-8">服务端实现</h3>
                
                <div class="mb-6">
                    <h4 class="font-semibold mb-2">Maven依赖</h4>
                    <div class="code-block">
                        <div class="code-header">
                            <span>pom.xml</span>
                            <span class="text-xs">GoEasy服务端依赖</span>
                        </div>
                        <pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;io.goeasy&lt;/groupId&gt;
    &lt;artifactId&gt;goeasy-sdk&lt;/artifactId&gt;
    &lt;version&gt;0.3.16&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
                    </div>
                </div>
                
                <h4 class="font-semibold mb-2">服务端发送消息</h4>
                <div class="code-block mb-6">
                    <div class="code-header">
                        <span>GoEasy服务端示例</span>
                        <span class="text-xs">消息发布</span>
                    </div>
                    <pre><code class="language-java">GoEasy goEasy = new GoEasy("http://rest-hangzhou.goeasy.io", "BC-1f35eadfecb44ba2838fe648c638f71f");

goEasy.publish("my_channel", "Hello GoEasy", new PublishListener() {
    @Override
    public void onSuccess() {
        System.out.println("Publish success.");
    }

    @Override
    public void onFailed(GoEasyError error) {
        System.out.println("Failed to Publish message, error:" + error.getCode() + " , " + error.getContent());
    }
});</code></pre>
                </div>
                
                <h3 class="text-xl font-semibold mb-4">客户端实现</h3>
                <div class="code-block">
                    <div class="code-header">
                        <span>HTML+JavaScript</span>
                        <span class="text-xs">客户端接收消息</span>
                    </div>
                    <pre><code class="language-html">&lt;script src="http://cdn-hangzhou.goeasy.io/goeasy.js"&gt;&lt;/script&gt;

&lt;script type="text/javascript"&gt;
    var goEasy = new GoEasy({
        appkey: "BC-1f35eadfecb44ba2838fe648c638f71f"
    });
    goEasy.subscribe({
        channel: "my_channel", // 被监听的channel
        onMessage: function (message) { // 客户端接收到消息的回调函数
            alert("Channel:" + message.channel + " content:" + message.content);
        }
    });
&lt;/script&gt;</code></pre>
                </div>
            </div>
        </section>
    </main>
    
    <!-- Footer -->
    <footer class="footer py-8 px-4">
        <div class="container mx-auto max-w-5xl text-center">
            <h3 class="text-xl font-semibold mb-2">技术小馆</h3>
            <p class="text-gray-400">
                <a href="http://www.yuque.com/jtostring" class="hover:text-white transition duration-300">http://www.yuque.com/jtostring</a>
            </p>
        </div>
    </footer>
    
    <script>
        // Initialize Mermaid
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: false,
                htmlLabels: true,
                curve: 'basis'
            }
        });
        
        // Smooth scrolling for anchor links
        document.querySelectorAll('a[href^="#"]').forEach(anchor => {
            anchor.addEventListener('click', function (e) {
                e.preventDefault();
                document.querySelector(this.getAttribute('href')).scrollIntoView({
                    behavior: 'smooth'
                });
            });
        });
    </script>
</body>
</html>